package com.mjgy.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.common.utils.PageUtils;
import com.common.utils.Query;
import com.common.utils.R;
import com.common.utils.RC4;
import com.mjgy.config.SysConfig;
import com.mjgy.entity.InviteCodeEntity;
import com.mjgy.entity.MUserEntity;
import com.mjgy.repository.InviteCodeRepository;
import com.mjgy.repository.MessageRepository;
import com.mjgy.service.InviteCodeService;

/**
* @Description: 邀请码
* @author LGC
* @date 2018年7月12日
* @version V1.0
*/
@Service("inviteCodeService")
@Transactional
public class InviteCodeServiceImpl implements InviteCodeService {

	@Autowired
	private InviteCodeRepository inviteCodeRepository;
	@Autowired
	private MessageRepository messageRepository;
	@Autowired
	private EntityManager entityManager;
	
	@Override
	public PageUtils queryPage(final Query query) {
		Specification<InviteCodeEntity> specification = new Specification<InviteCodeEntity>() {

			@Override
			public Predicate toPredicate(Root<InviteCodeEntity> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
				List<Predicate> predicates = new ArrayList<>();
				
				List<Predicate> orPredicates = new ArrayList<>();
				if(StringUtils.isNotBlank((String) query.get("area"))) {
					Predicate provinceLike = cb.like(root.<String>get("user").<String>get("province"), "%" + query.get("area") + "%");
					orPredicates.add(provinceLike);
					
					Predicate cityLike = cb.like(root.<String>get("user").<String>get("city"), "%" + query.get("area") + "%");
					orPredicates.add(cityLike);
					
					Predicate areaPredicate = cb.or(orPredicates.toArray(new Predicate[0]));
					predicates.add(areaPredicate);
				}
				
				if(StringUtils.isNotBlank((String) query.get("nickname"))) {
					Predicate nicknameLike = cb.like(root.<String>get("user").<String>get("nickname"), "%" + query.get("nickname") + "%");
					predicates.add(nicknameLike);
				}
				
				if(StringUtils.isNotBlank((String) query.get("phone"))) {
					Predicate phoneLike = cb.like(root.<String>get("user").<String>get("phone"), "%" + query.get("phone") + "%");
					predicates.add(phoneLike);
				}
				
				Predicate typePredicate = cb.equal(root.get("type").as(Integer.class), query.get("type"));
				predicates.add(typePredicate);
				return cb.and(predicates.toArray(new Predicate[0]));
			}
			
		};
		Pageable pageable = new PageRequest(query.getPage() - 1, query.getLimit(), new Sort(new Order(Direction.DESC, "applicationTime")));	
		Page<InviteCodeEntity> page = inviteCodeRepository.findAll(specification, pageable);
		// 解析用户信息
		List<Map<String, Object>> objList = new ArrayList<>();
		for(int i = 0; i < page.getContent().size(); i++) {
			Map<String, Object> map = new HashMap<>();
			InviteCodeEntity inviteCode = page.getContent().get(i);
			MUserEntity user = inviteCode.getUser();
			map.put("id", inviteCode.getId());
			map.put("username", user.getUsername());
			map.put("area", String.format("%s%s", user.getProvince(), user.getCity()));
			map.put("nickname", user.getNickname());
			map.put("applyCodeInfo", user.getApplyCodeInfo());
			map.put("wechat", user.getWechat());
			map.put("qq", user.getQq());
			map.put("applicationTime", inviteCode.getApplicationTime());
			map.put("inviteCode", inviteCode.getInviteCode());
			map.put("isUsed", inviteCode.isUsed() ? "已激活" : "未激活");
			objList.add(map);
		}
		PageUtils pageUtil = new PageUtils(objList, Long.valueOf(page.getTotalElements()).intValue(), query.getLimit(), query.getPage());
		
		return pageUtil;
	}

	@Override
	public R buildCode(Long id) {
		if(id == null) {
			return R.error(202, "邀请码ID不存在");
		}
		
		String code = RC4.encrypt(String.format("%07d", id), UUID.randomUUID().toString()).toUpperCase();
		InviteCodeEntity inviteCode = entityManager.find(InviteCodeEntity.class, id);
		if(StringUtils.isNotBlank(inviteCode.getInviteCode()) && inviteCode.isUsed()) {
			return R.error(203, "已生成邀请码");
		}
		
		//发送系统消息
//		MessageEntity messageEntity = new MessageEntity();
//		messageEntity.setUserId(inviteCode.getUser().getId());
//		messageEntity.setType("1");	//type=1表示系统消息
//		messageEntity.setContent("邀请码申请成功！【" + code + "】（点击可复制邀请码）");
//		messageEntity.setSendTime(new Date());
//		messageEntity.setIsChecked(0);	//未查阅
//		messageRepository.save(messageEntity);
		
		// 发送短信
		String product = SysConfig.messProduct;
		String domain = SysConfig.messDomain;
		String appKey = SysConfig.messAppKey;
		String appSecret = SysConfig.messAppSecret;
		String signName = SysConfig.messSignName;
		String templateCode = SysConfig.messInviteCode;
		String templateParam = "{\"code\":\"" + code + "\"}";
		
		try {
			// 初始化acsClient，暂不支持region化
			IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", appKey, appSecret);
			DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
			
			IAcsClient acsClient = new DefaultAcsClient(profile);
			
			// 组装请求对象
			SendSmsRequest request = new SendSmsRequest();
			if(StringUtils.isNotBlank(inviteCode.getUser().getPhone())) {
				request.setPhoneNumbers(inviteCode.getUser().getPhone());
			} else {
				request.setPhoneNumbers(inviteCode.getUser().getUsername());
			}
			request.setSignName(signName);
			request.setTemplateCode(templateCode);
			request.setTemplateParam(templateParam);
			
			SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
			if("OK".equals(sendSmsResponse.getCode())) {
				inviteCode.setInviteCode(code);
				entityManager.merge(inviteCode);
				R r = R.success("操作成功");
				return r;
			}else{
				return R.error(202, sendSmsResponse.getMessage());
			}
			
			
		} catch (ClientException e) {
			e.printStackTrace();
		}
		
		return R.error();
	}

	@Override
	public R applyCode(Long userId, int type) {
		MUserEntity user = entityManager.find(MUserEntity.class, userId);
		if(user == null) {
			return R.error(202, "用户不存在");
		}
		
		InviteCodeEntity icEntity = new InviteCodeEntity();
		icEntity.setApplicationTime(new Date());
		icEntity.setUser(user);
		icEntity.setType(type);
		entityManager.persist(icEntity);
		
		return R.success("操作成功");
	}

	@Override
	public R activateCode(Long userId, String inviteCode) {
		InviteCodeEntity icEntity = inviteCodeRepository.findOneByInviteCode(inviteCode);
		if(icEntity == null) {
			return R.error(202, "邀请码不存在，请联系客服");
		}
		
		if(icEntity.isUsed()) {
			return R.error(203, "邀请码已经使用过，不能重复激活");
		}
		
		// 激活了邀请码，用户才算完成注册
		MUserEntity user = entityManager.find(MUserEntity.class, userId);
		if(user.getSex() == 0 && user.getIdentity() == 1) {
			return R.error(204, "已经是会员，无需认证");
		}
		
		user.setStatus(true);
		user.setIdentity(3);
		entityManager.merge(user);
		
		icEntity.setUsed(true);
		entityManager.merge(icEntity);
		
		return R.success("操作成功");
	}

}
